package com.div.compiler

import com.div.annotation.TestAnnotation
import com.google.auto.common.BasicAnnotationProcessor
import com.google.common.collect.ImmutableSet
import com.google.common.collect.SetMultimap
import com.google.common.reflect.TypeToken
import com.squareup.kotlinpoet.*
import java.io.IOException
import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.Modifier
import javax.lang.model.element.VariableElement
import javax.lang.model.type.MirroredTypeException
import javax.lang.model.type.TypeMirror
import javax.lang.model.util.Types
import javax.tools.Diagnostic

class InjectGenerater(processingEnv: ProcessingEnvironment) : BorrowProcessingEnv(processingEnv),
        BasicAnnotationProcessor.ProcessingStep {

    private val SUFFIX = "_Utils"

    override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>?): MutableSet<out Element> {
        info("process : elementsByAnnotation= %s", elementsByAnnotation?.toString())
        for (element in elementsByAnnotation!![TestAnnotation::class.java]) {
            val toastClazz = ClassName("android.widget", "Toast")
            val contextClazz = ClassName("android.content", "Context")
            val className = createClassName(element)
            val file = FileSpec.builder(createPackage(element), className)
                    .addType(TypeSpec.classBuilder(className)
                            .addType(TypeSpec.companionObjectBuilder()
                                    .addFunction(FunSpec.builder("toast")
                                            .addParameter("context", contextClazz)
                                            .addParameter("msg", String::class)
                                            .addStatement("%T.makeText(context, msg, %T.LENGTH_SHORT).show()", toastClazz, toastClazz)
                                            .build())
                                    .build()
                            ).build())
                    .build()
            try {
                filer?.let { file.writeTo(it) }
            }catch (e: IOException) {
                error("write kotlin file IOException : %s", e.message)
            }
        }

        return ImmutableSet.of()
    }

    private fun createPackage(element: Element): String {
        return processingEnv.elementUtils?.getPackageOf(element)?.qualifiedName.toString()
    }

    private fun createClassName(element: Element): String {
        var className: String = ""
        try {
            val target = element.getAnnotation(TestAnnotation::class.java).target
            className = target.simpleName.toString()
        } catch (e: MirroredTypeException) {
//            info("MirroredTypeException : %s", e.toString())
            className = getTypeMirrorClassName(e.typeMirror)
        }
        return className + SUFFIX
    }

    /**
     * 获取类型名称不包含包路径
     * @param typeMirror TypeMirror
     * @return 名称
     */
    fun getTypeMirrorClassName(typeMirror: TypeMirror?): String {
        val split = typeMirror.toString().split(".")

        return ClassName("", split[split.size - 1]).simpleName
    }

    override fun annotations(): MutableSet<out Class<out Annotation>> {
        return ImmutableSet.of(TestAnnotation::class.java)
    }

    override fun info(msg: String?, vararg args: Any?) {
        messager?.printMessage(Diagnostic.Kind.NOTE, String.format(msg!!, *args))
    }

    override fun error(msg: String?, vararg args: Any?) {
        messager?.printMessage(Diagnostic.Kind.ERROR, String.format(msg!!, *args))
    }
}
